package org.andao.core.dao.helper;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.TreeMap;
import java.util.concurrent.ConcurrentHashMap;

import javax.servlet.ServletRequest;

import org.andao.core.utils.ExStringUtils;
import org.hibernate.criterion.Criterion;
import org.hibernate.criterion.Restrictions;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.Assert;


/**
 * 搜索过滤器.
 *
 * @author Seewo Software - Marco.hu(huzhiguo@cvte.cn)
 *
 */
public class QueryFilter {
	
	protected static Logger logger = LoggerFactory.getLogger(QueryFilter.class);
	
	public static enum Operator {
		EQ, // = 
		LIKE,// like 
		GT,  // >
		LT, // <
		GE, // >=
		LE, // <=
		IN, // in
		NOTIN,// not in
		ISNULL,// is null
		ISNOTNULL, //is not null
	}

	public String fieldName;
	public Object value;
	public Operator operator;

	public QueryFilter(String fieldName, Operator operator, Object value) {
		this.fieldName = fieldName;
		this.value = value;
		this.operator = operator;
	}

	/**
	 * 将搜索条件转换为criterion list.
	 * @param fileter
	 * @return
	 */
	public static Criterion[]  parsebySearchFilter(Map<String, QueryFilter> queryFilter){
		List<Criterion> objCriterion = new ArrayList<Criterion>();
		
		if(queryFilter != null && !queryFilter.isEmpty()){
			for(String field : queryFilter.keySet()){
				QueryFilter filter = queryFilter.get(field);				
				//可以自行扩增
				switch (filter.operator) {
				case EQ :
					objCriterion.add(Restrictions.eq(filter.fieldName,filter.value));
					break;
				case LIKE :
					objCriterion.add(Restrictions.ilike(filter.fieldName,"%"+filter.value+"%"));
					break;
				case GT:
					objCriterion.add(Restrictions.gt(filter.fieldName, filter.value));
					break;
				case LT:
					objCriterion.add(Restrictions.lt(filter.fieldName,  filter.value));
					break;
				case GE :
					objCriterion.add(Restrictions.ge(filter.fieldName,  filter.value));
					break;
				case LE:
					objCriterion.add(Restrictions.le(filter.fieldName,  filter.value));
					break;
				case IN:
					objCriterion.add(Restrictions.in(filter.fieldName,  (Collection)filter.value));
					break;
				case NOTIN:
					objCriterion.add(Restrictions.not(Restrictions.in(filter.fieldName,  (Collection)filter.value)));
					break;
				case ISNULL:
					objCriterion.add(Restrictions.isNull(filter.fieldName));
					break;
				case ISNOTNULL:
					objCriterion.add(Restrictions.isNotNull(filter.fieldName));
					break;
				}
			
			}
		}
		
		return objCriterion.toArray(new Criterion[objCriterion.size()]);
	}
	
	/**
	 * searchParams中key的格式为OPERATOR_FIELDNAME
	 */
	public static Map<String, QueryFilter> parse(Map<String, Object> searchParams) {
		Map<String, QueryFilter> filters = new HashMap<String,QueryFilter>();

		for (Entry<String, Object> entry : searchParams.entrySet()) {
			// 过滤掉空值
			String key = entry.getKey();
			Object value = entry.getValue();
			if (null == value) {
				continue;
			}

			// 拆分operator与filedAttribute
			String[] names = ExStringUtils.split(key, "_");
			if (names.length != 2) {
				//throw new IllegalArgumentException(key + " is not a valid search filter name");
				logger.warn("{} is not a valid search filter name", key);
				continue;
			}
			String filedName = names[1];
			Operator operator = Operator.valueOf(names[0]);

			// 创建searchFilter
			QueryFilter filter = new QueryFilter(filedName, operator, value);
			filters.put(key, filter);
		}

		return filters;
	}
	
	/**
	 * 从request中获取query paramenters,并取出search_前缀：search_EQ_resourceid --> EQ_resourceid.
	 * @param request
	 * @param prefix
	 * @return
	 */
	public static Map<String, Object> getQueryParametersFromRequest(ServletRequest request, String prefix) {
		Assert.notNull(request, "Request must not be null");
		Enumeration paramNames = request.getParameterNames();
		Map<String, Object> params = new TreeMap<String, Object>();
		if (prefix == null) {
			prefix = "";
		}
		while ((paramNames != null) && paramNames.hasMoreElements()) {
			String paramName = (String) paramNames.nextElement();
			if ("".equals(prefix) || paramName.startsWith(prefix)) {
				String unprefixed = paramName.substring(prefix.length());
				String[] values = request.getParameterValues(paramName);
				if ((values == null) || (values.length == 0)) {
					// Do nothing, no values found at all.
				} else if (values.length > 1) {
					params.put(unprefixed, values);
				} else {
					params.put(unprefixed, values[0]);
				}
			}
		}
		return params;
	}
	
	/**
	 * 组合Parameters生成Query String的Parameter部分, 并在paramter name上加上prefix:EQ_resourceid --> search_EQ_resourceid.
	 * @param params
	 * @param prefix
	 * @return
	 */
	public static Map<String,Object> prefixQueryParametersFromRequest(Map<String,Object> condition,String prefix){
		if ((condition == null) || (condition.size() == 0)) {
			return condition;
		}

		if (prefix == null) {
			prefix = "";
		}
		Map<String,Object> newCondition = new HashMap<String,Object>();
		String newkey = "";
		for(String key : condition.keySet()){			
			 if(ExStringUtils.split(key, "_").length>1){
				 newkey = prefix.concat(key);
			 }
			 
			 if(null != condition.get(key) && ExStringUtils.isNotBlank(newkey))
				 newCondition.put(newkey, condition.get(key));
		}
		return newCondition;
		
	}
	
	/**
	 * 使用别名方式替换Query Parameters中的key.
	 * @param condition
	 * @param alias resourceid = EQ_resourceid ...
	 * @return
	 */
	public static Map<String,Object> aliasParametersFromRequest(Map<String,Object> condition,String ... alias){
		if(null == alias || alias.length<1){
			return condition;
		}
		Map<String,Object> newCondition = new ConcurrentHashMap<String,Object>(condition);
		
		for(String key : newCondition.keySet()){
			for(String alia : alias){
				String[] arr = alia.split("=");
				if(arr.length == 2){
					if(key.equals(arr[1].trim()) && null != newCondition.get(key)){//若key相同，则替换								
						newCondition.put(arr[0].trim(), newCondition.get(key));
						newCondition.remove(key);
						break;
					}
				}
			}
		}
		
		
		
		return newCondition;
	}
	
}
